#include <GL/glut.h>
#include <GL/glu.h>

#include <cstddef>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdarg>

#include "vector3f.h"
#include "camera.h"
#include "mathUtils.h"
//#include <EasyBMP.h>

#include "game.h"

/* Enums and Typedefs *******/
enum {
	SCENE_1,
	SCENE_2
};
/***************************/
/* Global Variables ********/
int width=640, height=480;
int window;
int scene = SCENE_1;
Camera camera(Vector3f(2,0,0), Vector3f(-1,0,0), Vector3f(0,1,0));
GLuint texture, texture2;
char* _img;
/***************************/
/* Function Prototypes *****/
void centerMesh();
void idle();
void render();
void renderScene(int gl);
void reshape(int x, int y);
void initTweakBar();
/***************************/
/* Game Variables **********/
Game game(SPLIT_SCREEN, width, height);
//Game game(DUAL_SCREEN, width, height);
/***************************/

GLuint loadTexture(const char* filename) {
	/*GLuint texId;
	BMP bmpImage;
	bmpImage.ReadFromFile(filename);
	_img = new char[3 * bmpImage.TellWidth() * bmpImage.TellHeight()];
	int k=0;
	for(int j=bmpImage.TellHeight()-1; j>=0; j--)
		for(int i=0; i<bmpImage.TellWidth(); i++)
		{
			_img[k++] = bmpImage(i, j)->Red;
			_img[k++] = bmpImage(i, j)->Green;
			_img[k++] = bmpImage(i, j)->Blue;
		}

	glGenTextures(1, &texId);
	glBindTexture(GL_TEXTURE_2D, texId);

	glTexImage2D(GL_TEXTURE_2D,
				 0,
				 GL_RGB,
				bmpImage.TellWidth(), bmpImage.TellHeight(),
				 0,
				 GL_RGB,
				 GL_UNSIGNED_BYTE,
				 _img);
	return texId;
	*/
	return 0;
}

void drawText(const float x, const float y, const float z, void* font, const char* format, ...)
{
	int i, len;
	char str[500];

	glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT);
	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	va_list params;
	va_start(params, format);
	vsprintf(str, format, params);

	glRasterPos3f(x, y, z);
	for (i = 0, len = strlen(str); i < len; i++)
		glutBitmapCharacter(font, (int)str[i]);

	va_end(params);
	glPopAttrib();
}

void keyFunc(unsigned char key, int x, int y) {
	switch(key) {
		case 27: //ESC
		case 'q':
			exit(0);
			break;
	}
	game.keyboardFunc(key, x, y);
}

void idle() {
	render();
	game.update();
}

void renderSecurity() {
	glViewport(0, 0, width, height);

	GLuint tex=texture;
	if(scene == SCENE_1) {
		glClearColor(0.6, 0.6, 0.6, 1);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glColor4f(0.3, 0.3, 0.3, 1);
		tex = texture;
	}
	else {
		glClearColor(0.3, 0.3, 0.3, 1);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glColor4f(0.6, 0.6, 0.6, 1);
		tex = texture2;
	}

	for(int i=0; i<80; i++)
	{
		glBegin(GL_LINES);
			glVertex3f(-1, -1 + i*0.1, 0);
			glVertex3f(1, -1 + i*0.1, 0);
		glEnd();
	}
	
	/* tentativa textura (descomentar tambem o 'loadTexture' na 'main')
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	glBegin(GL_QUADS);
		glTexCoord2f(0, 0); glVertex3f(-1, -1, 0);
		glTexCoord2f(1, 0); glVertex3f(1, -1, 0);
		glTexCoord2f(1, 1); glVertex3f(1, 1, 0);
		glTexCoord2f(0, 1); glVertex3f(-1, 1, 0);
	glEnd();
	glDisable(GL_TEXTURE_2D);
	//*/

	drawText(0, 0, 0, GLUT_BITMAP_HELVETICA_18, "A hidden text!");
	scene = (scene == SCENE_1) ? SCENE_2 : SCENE_1;
}

void renderGame() {

	if(game.getGameMode() == SPLIT_SCREEN) {
		glClear(GL_COLOR_BUFFER_BIT);
		game.draw(0);
		game.draw(1);
	} else {
		if(scene == SCENE_1) {
			game.draw(0);
		} else {
			game.draw(1);
		}
		scene = (scene == SCENE_1) ? SCENE_2 : SCENE_1;
	}
}

void render() {
	/* Begin drawing scene */
	//renderSecurity();
	renderGame();
	/* End drawing scene */

	glutSwapBuffers();
	glutPostRedisplay();
}

void reshape(int x, int y)
{
	width = x; height = y;
	glutPositionWindow(0, 0);
	glutReshapeWindow(width, height);
	glMatrixMode(GL_VIEWPORT);
	glLoadIdentity();
	glViewport(0,0, width,height);
	game.reshapeFunc(width, height);
	glutPostRedisplay();
}

void initGL() {
	// Window
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA | GLUT_DEPTH);

	glutInitWindowPosition(25, 25);
	glutInitWindowSize(width, height);
	window = glutCreateWindow("Dual View Hide'n'Seek");

	glutFullScreen();

	glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

	// Culling
	//glEnable(GL_CULL_FACE);
	glFrontFace(GL_CCW);

	// Shading
	glShadeModel(GL_SMOOTH);
	glEnable(GL_NORMALIZE);

	// Alpha Blending
	//glEnable(GL_BLEND);
	//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// Lighting
	//glEnable(GL_LIGHTING);

	static const GLfloat specular[] = {1.0, 1.0, 1.0, 1.0};
	static const GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};
	static const GLfloat ambient[] = {0.2f, 0.2f, 0.2f};
	static const GLfloat position[] = {20.0f, 10.0f, 2.0f, 1.0f };
	glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
	glLightfv(GL_LIGHT0, GL_POSITION, position);

	glEnable(GL_LIGHT0);
	glEnable(GL_COLOR_MATERIAL);

	// Visibility
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);

	// Callbacks
	glutReshapeFunc(reshape);
	glutIdleFunc(idle);
	glutDisplayFunc(render);
	glutKeyboardFunc(keyFunc);
	//glutMouseFunc((GLUTmousebuttonfun)TwEventMouseButtonGLUT);
	//glutMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
	//glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
	//glutSpecialFunc((GLUTspecialfun)TwEventSpecialGLUT);
}

int main(int argc, char *argv[])
{
	printf("debug\n");
	glutInit(&argc, argv);
	initGL();
	//texture = loadTexture("text4.bmp");
	//texture2 = loadTexture("text2.bmp");
	glutMainLoop();
	return 0;
}
